package service_sys

import (
	"context"
	"fmt"
	"go_web/internal/global"
	"go_web/internal/model/model_sys"
	"go_web/internal/repo/repo_sys"
	"go_web/internal/req/req_sys"
	"go_web/internal/res/res_sys"
	"go_web/pkg/req"
	"go_web/pkg/res"
	"go_web/pkg/utils"
	"math"
	"time"

	"github.com/fatih/structs"
	"github.com/jinzhu/copier"
	"github.com/redis/go-redis/v9"
	"gorm.io/gen"
	"gorm.io/gen/field"
)

type SysAuthCodeService struct{}

// 创建新的 SysAuthCodeService
func NewSysAuthCodeService() *SysAuthCodeService {
	return &SysAuthCodeService{}
}

// 分页查询
func (*SysAuthCodeService) Page(c context.Context, pageReq req_sys.SysAuthCodePageReq) (*res.PageRes, error) {
	offset := (pageReq.Page - 1) * pageReq.PageSize
	q := repo_sys.SysAuthCode.WithContext(c)

	// 排序处理
	if pageReq.SortField != nil {
		sortField := utils.ConvertToSnakeCase(*pageReq.SortField)
		orderFieldExpr := field.NewUnsafeFieldRaw(sortField)
		if pageReq.SortOrder != nil {
			if *pageReq.SortOrder == "asc" {
				q = q.Order(orderFieldExpr.Asc())
			} else {
				q = q.Order(orderFieldExpr.Desc())
			}
		} else {
			q = q.Order(orderFieldExpr.Asc())
		}
	}

	// 执行分页查询
	list, count, err := q.FindByPage(offset, pageReq.PageSize)
	if err != nil {
		return nil, err
	}

	// 计算总页数
	page := res.PageRes{
		List:     list,
		Total:    count,
		Page:     pageReq.Page,
		PageSize: pageReq.PageSize,
		Pages:    int64(math.Ceil(float64(count) / float64(pageReq.PageSize))),
	}

	return &page, nil
}

// 添加 SysAuthCode 已开启事务
func (*SysAuthCodeService) Add(c context.Context, addReq req_sys.SysAuthCodeAddReq) (int64, error) {
	var SysAuthCode model_sys.SysAuthCode
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysAuthCode.WithContext(c)
		err := copier.Copy(&SysAuthCode, &addReq)
		if err != nil {
			return err
		}
		err = q.Create(&SysAuthCode)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return SysAuthCode.ID, nil
}

// 编辑 SysAuthCode 已开启事务
func (*SysAuthCodeService) Edit(c context.Context, editReq req_sys.SysAuthCodeEditReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := tx.SysAuthCode.WithContext(c).Where(repo_sys.SysAuthCode.ID.Eq(editReq.ID))
		SysAuthCode, err := q.First()
		if err != nil {
			return err
		}
		err = copier.Copy(&SysAuthCode, &editReq)
		if err != nil {
			return err
		}
		result, err = q.Updates(structs.Map(SysAuthCode))
		if err != nil {
			return err
		}
		return nil
	})

	if err != nil {
		if utils.IsOptimisticLockError(err) {
			return -1, nil // 乐观锁报错（版本不一致）
		}
		return 0, err
	}
	return result.RowsAffected, nil
}

// 删除 SysAuthCode 已开启事务
func (*SysAuthCodeService) Delete(c context.Context, idsReq req.IdsReq) (int64, error) {
	var result gen.ResultInfo
	err := repo_sys.Q.Transaction(func(tx *repo_sys.Query) error {
		q := repo_sys.SysAuthCode.WithContext(c)
		ids, err := idsReq.ToInt64Slice()
		if err != nil {
			return err
		}
		sysUserList, err := q.Where(repo_sys.SysUser.ID.In(ids...)).Find()
		if err != nil {
			return err
		}
		result, err = q.Delete(sysUserList...)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return 0, err
	}
	return result.RowsAffected, nil
}

// 查看 SysAuthCode 详情
func (*SysAuthCodeService) Detail(c context.Context, userId int64) (*model_sys.SysAuthCode, error) {
	q := repo_sys.SysAuthCode.WithContext(c)
	SysAuthCode, err := q.Where(repo_sys.SysAuthCode.ID.Eq(userId)).First()
	if err != nil {
		return nil, err
	}
	return SysAuthCode, nil
}

//func (*SysAuthCodeService) GetCode(c context.Context, codeKey string) (*res_sys.RetCode, error) {
//	qc := repo_sys.SysAuthCode.WithContext(c)
//	q := repo_sys.SysAuthCode
//	userIp := c.(*gin.Context).ClientIP()
//
//	// 减去五分钟
//	fiveMinutesAgo := time.Now().Add(-5 * time.Minute)
//
//	easyMathCode, err := qc.Where(
//		q.CodeKey.Like(userIp + ":EasyMathCode:")).Where(
//		q.ModifyTime.Lt(fiveMinutesAgo)).Find()
//	if err != nil {
//		return nil, err
//	}
//	if len(easyMathCode) > 0 {
//		_, err = qc.Unscoped().Delete(easyMathCode...)
//		if err != nil {
//			return nil, err
//		}
//	}
//	graphCode, err := qc.Where(
//		q.CodeKey.Like(userIp + ":GraphCode:")).Where(
//		q.ModifyTime.Lt(fiveMinutesAgo)).Find()
//	if err != nil {
//		return nil, err
//	}
//	if len(graphCode) > 0 {
//		_, err = qc.Unscoped().Delete(graphCode...)
//		if err != nil {
//			return nil, err
//		}
//	}
//
//	keyNums, err := qc.Where(q.CodeKey.Like(userIp + ":" + codeKey + ":")).Count()
//	if err != nil {
//		return nil, err
//	}
//	if keyNums >= 50 {
//		return nil, fmt.Errorf("请求次数过多")
//	}
//	var imgCaptcha *res_sys.ImgCaptcha
//	switch codeKey {
//	case "GraphCode":
//		{
//			imgCaptcha, err = utils.GenerateGraphValidateCode()
//			if err != nil {
//				return nil, err
//			}
//			break
//		}
//	case "EasyMathCode":
//		{
//			imgCaptcha, err = utils.GenerateEasyMathValidateCode()
//			if err != nil {
//				return nil, err
//			}
//			break
//		}
//	}
//	if imgCaptcha == nil {
//		return nil, fmt.Errorf("验证码生成失败")
//	}
//	err = qc.Create(&model_sys.SysAuthCode{
//		CodeKey: userIp + ":" + codeKey + ":" + imgCaptcha.ValidCode,
//		CodeVal: imgCaptcha.Code,
//	})
//	if err != nil {
//		return nil, err
//	}
//	retCode := &res_sys.RetCode{
//		Base64:    imgCaptcha.Base64,
//		ValidCode: imgCaptcha.ValidCode,
//	}
//	return retCode, nil
//}

func (*SysAuthCodeService) GetCode(c context.Context, codeKey string) (*res_sys.RetCode, error) {
	var imgCaptcha *res_sys.ImgCaptcha
	var err error
	switch codeKey {
	case "GraphCode":
		{
			imgCaptcha, err = utils.GenerateGraphValidateCode()
			if err != nil {
				return nil, err
			}
			break
		}
	case "EasyMathCode":
		{
			imgCaptcha, err = utils.GenerateEasyMathValidateCode()
			if err != nil {
				return nil, err
			}
			break
		}
	}
	if imgCaptcha == nil {
		return nil, fmt.Errorf("验证码生成失败")
	}

	retCode := &res_sys.RetCode{
		Base64:    imgCaptcha.Base64,
		ValidCode: imgCaptcha.ValidCode,
	}
	return retCode, nil
}

// 发送邮件验证码
func (*SysAuthCodeService) SendEmailCode(c context.Context, email, username, clientIp string) error {
	if username != "" {
		q := repo_sys.SysUser.WithContext(c)
		user, err := q.Where(repo_sys.SysUser.Username.Eq(username)).First()
		if err != nil {
			return err
		}
		if user == nil {
			return fmt.Errorf("用户不存在")
		}
		sysUserBind, err := repo_sys.SysUserBind.WithContext(c).Where(repo_sys.SysUserBind.UserID.Eq(user.ID)).
			Where(repo_sys.SysUserBind.BindContent.Eq(email)).First()
		if err != nil {
			return err

		}
		if sysUserBind == nil {
			return fmt.Errorf("该用户未绑定此邮箱")
		}
		isDisableResend := global.Redis.Get(c, clientIp+":"+username+":email:code:disableResend"+email)
		if isDisableResend.Err() == redis.Nil {
			code := utils.GenerateStrCode(6)
			err := utils.SendEmail(email, "邮箱验证码", "您的验证码是："+code)
			if err != nil {
				return err
			}
			global.Redis.Set(c, clientIp+":"+username+":email:code:"+email, code, 5*time.Minute)
			global.Redis.Set(c, clientIp+":"+username+":email:code:disableResend"+email, true, 1*time.Minute)
			htmlBody := "<html><body>" +
				"您的验证码：<b><u style='color: red; font-size: 16px;'>" + code + "</u></b>，" +
				"【对应用户名：" + username + "】如非本人操作，请勿理会！（验证码有效期 5分钟）" +
				"</body></html>"
			err = utils.SendEmail(email, "YuCodesSpace 【邮箱验证码服务】", htmlBody)
			if err != nil {
				return err
			}
		} else {
			return fmt.Errorf("请勿重复发送验证码")
		}
	} else {
		isDisableResend := global.Redis.Get(c, clientIp+":email:code:disableResend"+email)
		if isDisableResend.Err() == redis.Nil {
			code := utils.GenerateStrCode(6)
			global.Redis.Set(c, clientIp+":email:code:"+email, code, 5*time.Minute)
			global.Redis.Set(c, clientIp+":email:code:disableResend"+email, true, 1*time.Minute)
			htmlBody := "<html><body>" +
				"您的验证码：<b><u style='color: red; font-size: 16px;'>" + code + "</u></b>，" +
				"如非本人操作，请勿理会！（验证码有效期 5分钟）" +
				"</body></html>"
			err := utils.SendEmail(email, "YuCodesSpace 【邮箱验证码服务】", htmlBody)
			if err != nil {
				return err
			}
			return nil
		} else {
			return fmt.Errorf("请勿重复发送验证码")
		}
	}
	return fmt.Errorf("未知错误")
}
